package ai.zixing.framework.context.support;

import ai.zixing.framework.beans.BeanDefinition;
import ai.zixing.framework.beans.MutablePropertyValues;
import ai.zixing.framework.beans.PropertyValue;
import ai.zixing.framework.beans.factory.support.BeanDefinitionRegistry;
import ai.zixing.framework.beans.factory.xml.XmlBeanDefinitionReader;
import ai.zixing.framework.utils.SpringUtils;

import java.lang.reflect.Method;

/**
 * IOC 容器具体的子实现类，加载 XML 格式的配置文件
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    public ClassPathXmlApplicationContext(String configLocation) {
        super.configLocation = configLocation;
        // 构建解析器对象,指定具体解析器类为 XML
        this.beanDefinitionReader = new XmlBeanDefinitionReader();
        // 调用父类的 refresh()
        this.refresh();
    }

    // 根据 bean 对象名称获取 bean 对象
    @Override
    public Object getBean(String name) throws Exception {
        // 判断对象容器中是否包含指定名称的 bean 对象，有则返回，没有则创建
        Object obj = singletonObjects.get(name);
        if (obj != null) {
            return obj;
        }
        // 自行创建
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        // 通过反射创建对象
        String className = beanDefinition.getClassName();
        Class<?> clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();
        // 需要进行依赖注入
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            // 获取 property 标签的属性
            String pName = propertyValue.getName();
            String pRef = propertyValue.getRef();
            String pValue = propertyValue.getValue();
            if (pRef != null && !pRef.isEmpty()) {
                // 获取依赖的 bean 对象
                Object bean = getBean(pRef);
                // setCourseDao() set + courseDao
                String methodName = SpringUtils.getSetterMethod(pName);
                // 获取所有方法对象
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (methodName.equals(method.getName())) {
                        // 执行方法
                        method.invoke(beanObj, bean);
                    }
                }
            }
            if (pValue != null && !pValue.isEmpty()) {
                String methodName = SpringUtils.getSetterMethod(pName);
                // 获取 method
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj, pValue);
            }
        }
        // 在返回 beanObj 之前，需要将对象存储到 Map 中
        this.singletonObjects.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) {
        Object bean = null;
        try {
            bean = getBean(name);
            if (bean == null) {
                return null;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return clazz.cast(bean);
    }
}
